# -*- coding: utf-8 -*-
"""
安全属性访问工具 - 统一的属性访问方法
提供安全的对象属性访问，避免AttributeError异常
"""

import logging
from typing import Any, Optional, Dict, List, Union, Callable
from functools import wraps

# 尝试导入增强日志系统
try:
    from core.enhanced_logger import get_logger
    logger = get_logger(__name__)
except ImportError:
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)

# 尝试导入错误处理系统
try:
    from core.error_handler import error_handler, ErrorSeverity, ErrorCategory
except ImportError:
    def error_handler(severity=None, category=None):
        def decorator(func):
            return func
        return decorator
    
    class ErrorSeverity:
        LOW = "low"
        MEDIUM = "medium"
        HIGH = "high"
        CRITICAL = "critical"
    
    class ErrorCategory:
        ATTRIBUTE = "attribute"
        VALIDATION = "validation"
        EXECUTION = "execution"


class SafeAttributeAccessor:
    """安全属性访问器"""
    
    def __init__(self):
        self.access_log = []
        self.error_count = 0
        self.success_count = 0
    
    @error_handler(severity=ErrorSeverity.LOW, category=ErrorCategory.ATTRIBUTE)
    def safe_getattr(self, obj: Any, attr_name: str, default: Any = None, 
                     log_access: bool = False) -> Any:
        """
        安全获取对象属性
        
        Args:
            obj: 目标对象
            attr_name: 属性名称
            default: 默认值
            log_access: 是否记录访问日志
            
        Returns:
            属性值或默认值
        """
        try:
            if hasattr(obj, attr_name):
                value = getattr(obj, attr_name)
                self.success_count += 1
                
                if log_access:
                    self.access_log.append({
                        'object_type': type(obj).__name__,
                        'attribute': attr_name,
                        'success': True,
                        'value_type': type(value).__name__
                    })
                
                return value
            else:
                self.error_count += 1
                
                if log_access:
                    self.access_log.append({
                        'object_type': type(obj).__name__,
                        'attribute': attr_name,
                        'success': False,
                        'error': 'AttributeNotFound'
                    })
                
                logger.warning(f"属性 '{attr_name}' 在对象 {type(obj).__name__} 中不存在，返回默认值")
                return default
                
        except Exception as e:
            self.error_count += 1
            
            if log_access:
                self.access_log.append({
                    'object_type': type(obj).__name__,
                    'attribute': attr_name,
                    'success': False,
                    'error': str(e)
                })
            
            logger.error(f"访问属性 '{attr_name}' 时发生异常: {e}")
            return default
    
    @error_handler(severity=ErrorSeverity.LOW, category=ErrorCategory.ATTRIBUTE)
    def safe_setattr(self, obj: Any, attr_name: str, value: Any, 
                     create_if_missing: bool = True) -> bool:
        """
        安全设置对象属性
        
        Args:
            obj: 目标对象
            attr_name: 属性名称
            value: 属性值
            create_if_missing: 如果属性不存在是否创建
            
        Returns:
            是否设置成功
        """
        try:
            if hasattr(obj, attr_name) or create_if_missing:
                setattr(obj, attr_name, value)
                self.success_count += 1
                logger.debug(f"成功设置属性 '{attr_name}' = {value}")
                return True
            else:
                self.error_count += 1
                logger.warning(f"属性 '{attr_name}' 不存在且不允许创建")
                return False
                
        except Exception as e:
            self.error_count += 1
            logger.error(f"设置属性 '{attr_name}' 时发生异常: {e}")
            return False
    
    @error_handler(severity=ErrorSeverity.LOW, category=ErrorCategory.ATTRIBUTE)
    def safe_hasattr(self, obj: Any, attr_name: str) -> bool:
        """
        安全检查对象是否有指定属性
        
        Args:
            obj: 目标对象
            attr_name: 属性名称
            
        Returns:
            是否有该属性
        """
        try:
            return hasattr(obj, attr_name)
        except Exception as e:
            logger.error(f"检查属性 '{attr_name}' 时发生异常: {e}")
            return False
    
    @error_handler(severity=ErrorSeverity.MEDIUM, category=ErrorCategory.ATTRIBUTE)
    def safe_getattr_chain(self, obj: Any, attr_chain: str, default: Any = None) -> Any:
        """
        安全获取链式属性 (如 obj.attr1.attr2.attr3)
        
        Args:
            obj: 目标对象
            attr_chain: 属性链 (用点分隔)
            default: 默认值
            
        Returns:
            属性值或默认值
        """
        try:
            current_obj = obj
            attrs = attr_chain.split('.')
            
            for attr in attrs:
                if not hasattr(current_obj, attr):
                    logger.warning(f"属性链 '{attr_chain}' 在 '{attr}' 处中断")
                    return default
                current_obj = getattr(current_obj, attr)
            
            self.success_count += 1
            return current_obj
            
        except Exception as e:
            self.error_count += 1
            logger.error(f"访问属性链 '{attr_chain}' 时发生异常: {e}")
            return default
    
    @error_handler(severity=ErrorSeverity.MEDIUM, category=ErrorCategory.ATTRIBUTE)
    def safe_call_method(self, obj: Any, method_name: str, *args, **kwargs) -> Any:
        """
        安全调用对象方法
        
        Args:
            obj: 目标对象
            method_name: 方法名称
            *args: 位置参数
            **kwargs: 关键字参数
            
        Returns:
            方法返回值或None
        """
        try:
            if hasattr(obj, method_name):
                method = getattr(obj, method_name)
                if callable(method):
                    result = method(*args, **kwargs)
                    self.success_count += 1
                    return result
                else:
                    logger.warning(f"'{method_name}' 不是可调用的方法")
                    return None
            else:
                logger.warning(f"方法 '{method_name}' 在对象 {type(obj).__name__} 中不存在")
                return None
                
        except Exception as e:
            self.error_count += 1
            logger.error(f"调用方法 '{method_name}' 时发生异常: {e}")
            return None
    
    @error_handler(severity=ErrorSeverity.LOW, category=ErrorCategory.ATTRIBUTE)
    def get_object_attributes(self, obj: Any, include_private: bool = False) -> List[str]:
        """
        获取对象的所有属性列表
        
        Args:
            obj: 目标对象
            include_private: 是否包含私有属性
            
        Returns:
            属性名称列表
        """
        try:
            attrs = dir(obj)
            if not include_private:
                attrs = [attr for attr in attrs if not attr.startswith('_')]
            return attrs
        except Exception as e:
            logger.error(f"获取对象属性列表时发生异常: {e}")
            return []
    
    @error_handler(severity=ErrorSeverity.LOW, category=ErrorCategory.ATTRIBUTE)
    def get_attribute_info(self, obj: Any, attr_name: str) -> Dict[str, Any]:
        """
        获取属性的详细信息
        
        Args:
            obj: 目标对象
            attr_name: 属性名称
            
        Returns:
            属性信息字典
        """
        info = {
            'exists': False,
            'type': None,
            'value': None,
            'callable': False,
            'doc': None
        }
        
        try:
            if hasattr(obj, attr_name):
                info['exists'] = True
                attr_value = getattr(obj, attr_name)
                info['type'] = type(attr_value).__name__
                info['callable'] = callable(attr_value)
                
                # 对于简单类型，记录值
                if isinstance(attr_value, (str, int, float, bool, list, dict)):
                    info['value'] = attr_value
                
                # 获取文档字符串
                if hasattr(attr_value, '__doc__'):
                    info['doc'] = attr_value.__doc__
                    
        except Exception as e:
            logger.error(f"获取属性 '{attr_name}' 信息时发生异常: {e}")
        
        return info
    
    def get_access_statistics(self) -> Dict[str, Any]:
        """获取访问统计信息"""
        total_access = self.success_count + self.error_count
        success_rate = (self.success_count / total_access * 100) if total_access > 0 else 0
        
        return {
            'total_access': total_access,
            'successful_access': self.success_count,
            'failed_access': self.error_count,
            'success_rate': f"{success_rate:.1f}%",
            'recent_access_log': self.access_log[-10:] if self.access_log else []
        }
    
    def clear_statistics(self):
        """清除统计信息"""
        self.access_log.clear()
        self.error_count = 0
        self.success_count = 0


# 全局安全属性访问器实例
safe_accessor = SafeAttributeAccessor()


def safe_getattr(obj: Any, attr_name: str, default: Any = None) -> Any:
    """全局安全属性获取函数"""
    return safe_accessor.safe_getattr(obj, attr_name, default)


def safe_setattr(obj: Any, attr_name: str, value: Any) -> bool:
    """全局安全属性设置函数"""
    return safe_accessor.safe_setattr(obj, attr_name, value)


def safe_hasattr(obj: Any, attr_name: str) -> bool:
    """全局安全属性检查函数"""
    return safe_accessor.safe_hasattr(obj, attr_name)


def safe_getattr_chain(obj: Any, attr_chain: str, default: Any = None) -> Any:
    """全局安全链式属性获取函数"""
    return safe_accessor.safe_getattr_chain(obj, attr_chain, default)


def safe_call_method(obj: Any, method_name: str, *args, **kwargs) -> Any:
    """全局安全方法调用函数"""
    return safe_accessor.safe_call_method(obj, method_name, *args, **kwargs)


def safe_attribute_access(func: Callable) -> Callable:
    """
    安全属性访问装饰器
    自动将函数中的属性访问转换为安全访问
    """
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except AttributeError as e:
            logger.warning(f"函数 {func.__name__} 中发生属性访问错误: {e}")
            # 可以在这里添加自动修复逻辑
            raise
    return wrapper


# 便捷的属性访问类
class SafeObject:
    """安全对象包装器"""
    
    def __init__(self, obj: Any):
        self._wrapped_obj = obj
        self._accessor = SafeAttributeAccessor()
    
    def __getattr__(self, name: str) -> Any:
        return self._accessor.safe_getattr(self._wrapped_obj, name)
    
    def __setattr__(self, name: str, value: Any) -> None:
        if name.startswith('_'):
            super().__setattr__(name, value)
        else:
            self._accessor.safe_setattr(self._wrapped_obj, name, value)
    
    def __hasattr__(self, name: str) -> bool:
        return self._accessor.safe_hasattr(self._wrapped_obj, name)
    
    def get_wrapped_object(self) -> Any:
        """获取被包装的原始对象"""
        return self._wrapped_obj
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取访问统计"""
        return self._accessor.get_access_statistics()


def wrap_object(obj: Any) -> SafeObject:
    """将对象包装为安全对象"""
    return SafeObject(obj)


if __name__ == "__main__":
    # 测试代码
    class TestObject:
        def __init__(self):
            self.existing_attr = "test_value"
            self.number = 42
        
        def test_method(self, arg):
            return f"Method called with: {arg}"
    
    # 创建测试对象
    test_obj = TestObject()
    
    # 测试安全属性访问
    print("=== 安全属性访问测试 ===")
    
    # 存在的属性
    value1 = safe_getattr(test_obj, 'existing_attr', 'default')
    print(f"existing_attr: {value1}")
    
    # 不存在的属性
    value2 = safe_getattr(test_obj, 'non_existing_attr', 'default_value')
    print(f"non_existing_attr: {value2}")
    
    # 链式属性访问
    value3 = safe_getattr_chain(test_obj, 'existing_attr.upper', lambda: 'DEFAULT')
    print(f"链式访问结果: {value3}")
    
    # 方法调用
    result = safe_call_method(test_obj, 'test_method', 'hello')
    print(f"方法调用结果: {result}")
    
    # 获取属性信息
    info = safe_accessor.get_attribute_info(test_obj, 'existing_attr')
    print(f"属性信息: {info}")
    
    # 获取统计信息
    stats = safe_accessor.get_access_statistics()
    print(f"访问统计: {stats}")
    
    # 测试安全对象包装器
    print("\n=== 安全对象包装器测试 ===")
    safe_obj = wrap_object(test_obj)
    print(f"包装对象访问: {safe_obj.existing_attr}")
    print(f"包装对象访问不存在属性: {safe_obj.non_existing}")